﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace ESP.Data
{
    public class OrderbyCommandParameters : CommandParameters
    {
        private IEnumerable<LambdaExpression> _expressions;
        private Dictionary<object, string> _tableMappings;

        public OrderbyCommandParameters(string token, IEnumerable<LambdaExpression> expressions, Dictionary<object, string> tableMappings = null)
            : base(token)
        {
            _expressions = expressions;
            _tableMappings = tableMappings;
        }

        protected internal override void Build()
        {
            SubParameters.Add(string.Empty, TranslatePredicate());
        }

        private string TranslatePredicate()
        {
            StringBuilder builder = new StringBuilder();

            bool isFirst = true;
            foreach (var exp in _expressions)
            {
                if (!isFirst)
                {
                    builder.Append(", ");
                }
                else
                {
                    isFirst = false;
                }
                TranslateOrderbyExpression(builder, exp.Body, GetParameterTableNameMappings(exp.Parameters, _tableMappings));
            }

            return builder.ToString();
        }

        private void TranslateOrderbyExpression(StringBuilder builder, Expression expression, Dictionary<ParameterExpression, string> parameterMappings)
        {
            var body = (MethodCallExpression)expression;
            if (body.Method.DeclaringType != typeof(OrderbyExtensions))
                throw new InvalidCastException();

            var arg0 = body.Arguments[0];
            if (arg0.NodeType == ExpressionType.Convert)
            {
                arg0 = ((System.Linq.Expressions.UnaryExpression)arg0).Operand;
            }
            var orderby = (MemberExpression)arg0;

            var tableExpression = (ParameterExpression)orderby.Expression;
            string column = orderby.Member.Name;

            string tableName;
            if (parameterMappings.TryGetValue(tableExpression, out tableName))
            {
                builder.Append(QuoteName(tableName));
                builder.Append(".");
            }

            builder.Append("[").Append(column).Append("]");

            string methodName = body.Method.Name;

            if (methodName == "Ascending")
            {
                builder.Append(" ASC");
            }
            else if (methodName == "Descending")
            {
                builder.Append(" DESC");
            }
        }
    }
}
